package com.ctshk.rpc.order.tour.service.impl;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.ctshk.common.enums.*;
import com.ctshk.common.utils.SnowflakeIdWorker;
import com.ctshk.common.vo.OrderRefundDTO;
import com.ctshk.rpc.finance.json.AccountJson;
import com.ctshk.rpc.finance.req.bill.BillAddRefundReq;
import com.ctshk.rpc.finance.req.bill.BillOperateRefundReq;
import com.ctshk.rpc.finance.service.IFinanceBillService;
import com.ctshk.rpc.order.tour.dto.*;
import com.ctshk.rpc.order.tour.entity.*;
import com.ctshk.rpc.order.tour.mapper.*;
import com.ctshk.rpc.order.tour.req.*;
import com.ctshk.rpc.system.dto.UserDTO;
import com.ctshk.rpc.system.service.ISysUserService;
import com.ctshk.rpc.tour.dto.schedule.SeriesTripScheduleDTO;
import com.ctshk.rpc.tour.service.ISeriesTripScheduleService;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.dto.Result;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.model.PageResponse;
import com.ctshk.common.model.TokenUser;
import com.ctshk.common.service.support.BaseService;
import com.ctshk.common.utils.EntityUtil;
import com.ctshk.rpc.insurance.req.tp.CancelReq;
import com.ctshk.rpc.insurance.service.IInsuranceService;
import com.ctshk.rpc.order.tour.code.CollectionRefundWayIdCode;
import com.ctshk.rpc.order.tour.code.CollectionTypeIdCode;
import com.ctshk.rpc.order.tour.code.CurrencyIdCode;
import com.ctshk.rpc.order.tour.code.ISCode;
import com.ctshk.rpc.order.tour.code.IsDeletedCode;
import com.ctshk.rpc.order.tour.code.RefundDetailTypeCode;
import com.ctshk.rpc.order.tour.code.RefundStatusCode;
import com.ctshk.rpc.order.tour.code.SeriesOrderErrorCode;
import com.ctshk.rpc.order.tour.service.ISeriesOrderCollectionService;
import com.ctshk.rpc.order.tour.service.ISeriesOrderReceiptDetailsService;
import com.ctshk.rpc.order.tour.service.ISeriesOrderService;
import com.ctshk.rpc.order.tour.service.ISeriesOrderTouristOtherFeeService;
import com.ctshk.rpc.order.tour.service.ISeriesOrderTouristRefundService;
import com.ctshk.rpc.order.tour.util.PacificUtil;
import com.ctshk.rpc.system.dto.MainDataCurrencyQueryDTO;
import com.ctshk.rpc.system.req.MainDataCurrencyUpdateStatusReq;
import com.ctshk.rpc.system.service.IMainDataCurrencyService;
import com.ctshk.rpc.workflow.dto.ApprovalCheckDTO;
import com.ctshk.rpc.workflow.dto.ApprovalStartDTO;
import com.ctshk.rpc.workflow.service.ISysApprovalService;
import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 系列团游客退款记录 服务实现类
 * </p>
 *
 * @author 谭响
 * @since 2021-01-28
 */
@Slf4j
@DubboService
public class SeriesOrderTouristRefundServiceImpl extends ServiceImpl<SeriesOrderTouristRefundMapper, SeriesOrderTouristRefund> implements ISeriesOrderTouristRefundService, BaseService {

    @Autowired
    private SeriesOrderTouristRefundMapper seriesOrderTouristRefundMapper;
    @Autowired
    private SeriesOrderTouristRefundDetailMapper seriesOrderTouristRefundDetailMapper;
    @Autowired
    private SeriesOrderTouristInfoMapper seriesOrderTouristInfoMapper;
    @Autowired
    private SeriesOrderAmountStatisticsMapper seriesOrderAmountStatisticsMapper;
    @Autowired
    private SeriesOrderTouristVisaMapper seriesOrderTouristVisaMapper;
    @Autowired
    private SeriesOrderTouristOtherFeeMapper seriesOrderTouristOtherFeeMapper;
    @Autowired
    private SeriesOrderMapper seriesOrderMapper;
    @Autowired
    private SeriesOrderCollectionMapper seriesOrderCollectionMapper;
    @Autowired
    private SeriesOrderReceiptDetailsMapper seriesOrderReceiptDetailsMapper;

    private ISeriesOrderCollectionService iSeriesOrderCollectionService;
    @DubboReference
    private IMainDataCurrencyService iMainDataCurrencyService;
    @DubboReference
    private IInsuranceService iInsuranceService;
    private ISeriesOrderReceiptDetailsService iSeriesOrderReceiptDetailsService;
    @DubboReference
    private ISysApprovalService iSysApprovalService;
    @Autowired
    private ISeriesOrderService iSeriesOrderService;
    private ISeriesOrderTouristOtherFeeService iSeriesOrderTouristOtherFeeService;
    @DubboReference
    private IFinanceBillService financeBillService;
    @DubboReference
    private ISeriesTripScheduleService iSeriesTripScheduleService;
    @DubboReference
    private ISysUserService iSysUserService;



    /**
     * 列表
     */
    @Override
    public PageResponse<SeriesOrderTouristRefundListDTO> list(SeriesOrderTouristRefundListReq req) {
        IPage<SeriesOrderTouristRefundListReq> pageParam = new Page<>(req.getPageNo(), req.getPageSize());
        IPage<SeriesOrderTouristRefundListDTO> pageResult = seriesOrderTouristRefundMapper.selectListBySelective(pageParam, req);
        PageResponse<SeriesOrderTouristRefundListDTO> pageResponse = new PageResponse<>(pageResult.getRecords(),
                pageResult.getCurrent() == 1,
                pageResult.getTotal() <= (pageResult.getCurrent() * pageResult.getSize()),
                pageResult.getTotal(), pageResult.getCurrent(),
                pageResult.getSize());
        return pageResponse;
    }

    /**
     * 添加
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result add(SeriesOrderTouristRefundAddReq req) {
        //明细不能重复录入
        int insurance = 0;
        int visa = 0;
        for (SeriesOrderTouristRefundAddItemReq itemReq : req.getItemList()) {
            if (Objects.equals(RefundDetailTypeCode.INSURANCE.getCode(), itemReq.getRefundDetailTypeId())) {
                insurance++;
            }
            if (Objects.equals(RefundDetailTypeCode.VISA.getCode(), itemReq.getRefundDetailTypeId())) {
                visa++;
            }
        }
        if (insurance >= 2) {
            return Result.failed(SeriesOrderErrorCode.REPEAT_REFUND_INSURANCE_LIMIT);
        }
        if (visa >= 2) {
            return Result.failed(SeriesOrderErrorCode.REPEAT_REFUND_VISA_LIMIT);
        }

        //保险/签证，只能退款一次
        Set<Long> refundDetailTypeIdSet = new HashSet<>();
        refundDetailTypeIdSet.add(RefundDetailTypeCode.INSURANCE.getCode());
        refundDetailTypeIdSet.add(RefundDetailTypeCode.VISA.getCode());
        List<SeriesOrderTouristRefundDetail> dbDetailList = seriesOrderTouristRefundMapper.selectAddByRefundDetailTypeId(
                req, refundDetailTypeIdSet);
        for (SeriesOrderTouristRefundDetail detail : dbDetailList) {
            if (Objects.equals(RefundDetailTypeCode.INSURANCE.getCode(), detail.getRefundDetailTypeId())) {
                return Result.failed(SeriesOrderErrorCode.REPEAT_REFUND_INSURANCE_LIMIT);
            }
            if (Objects.equals(RefundDetailTypeCode.VISA.getCode(), detail.getRefundDetailTypeId())) {
                return Result.failed(SeriesOrderErrorCode.REPEAT_REFUND_VISA_LIMIT);
            }
        }

        LocalDateTime now = LocalDateTime.now();

        //游客统计
        QueryWrapper<SeriesOrderTouristInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(SeriesOrderTouristInfo::getOrderId, req.getOrderId());
        queryWrapper.lambda().eq(SeriesOrderTouristInfo::getId, req.getTouristId());
        queryWrapper.lambda().eq(SeriesOrderTouristInfo::getIsDeleted, IsDeletedCode.NO.getCode());
        SeriesOrderTouristInfo touristInfo = seriesOrderTouristInfoMapper.selectOne(queryWrapper);
        if (touristInfo == null) {
            return Result.failed(SystemError.SYS_411);
        }
        if(touristInfo.getTotalPaidIn().compareTo(new BigDecimal(0)) <= 0) {
            return Result.failed(SeriesOrderErrorCode.REFUND_AMOUNT_EXIST_LIMIT);
        }

        //订单统计
        QueryWrapper<SeriesOrderAmountStatistics> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.lambda().eq(SeriesOrderAmountStatistics::getOrderId, req.getOrderId());
        SeriesOrderAmountStatistics statistics = seriesOrderAmountStatisticsMapper.selectOne(queryWrapper2);

        if (statistics == null) {
            return Result.failed((SystemError.SYS_411));
        }

        //实收
        BigDecimal totalPaidIn = touristInfo.getTotalPaidIn();
        //调整费用
        BigDecimal adjustmentCost = touristInfo.getAdjustmentCost();
        //退款记录
        Long refundId = IdWorker.getId();
        SeriesOrderTouristRefund refund = EntityUtil.copy(req, SeriesOrderTouristRefund.class);
        refund.setRefundNumber(iSeriesOrderService.getRefundNumber());
        refund.setRefundStatus(2);
        refund.setId(refundId);
        refund.setGmtCreate(now);
        refund.setGmtModified(now);
        refund.setCreateId(req.getUserId());
        refund.setIsDeleted(IsDeletedCode.NO.getCode());
        refund.setRefundStatus(RefundStatusCode.APPROVAL.getCode());
        int insertRefund = seriesOrderTouristRefundMapper.insert(refund);
        if (insertRefund <= 0){
            throw new BusinessException(SystemError.SYS_437);
        }
        BigDecimal totalRefundAmount = BigDecimal.ZERO;
        List<SeriesOrderTouristRefundDetail> refundDetailList = new ArrayList<>();
        List<Long> refundIdList = new ArrayList<>();
        for (SeriesOrderTouristRefundAddItemReq itemReq : req.getItemList()) {
            SeriesOrderTouristRefundDetail detail = EntityUtil.copy(itemReq, SeriesOrderTouristRefundDetail.class);

            //退款金额 港幣金額=其他貨幣金額×對應的門市匯率
            BigDecimal refundAmount = itemReq.getCurrencyRefundAmount();
            if(!Objects.equals(CurrencyIdCode.HKD.getCode(), itemReq.getCurrencyTypeId())) {
                refundAmount = iMainDataCurrencyService.getHkdAmount(itemReq.getCurrencyTypeId(), itemReq.getCurrencyRefundAmount());
            }
            totalRefundAmount = totalRefundAmount.add(refundAmount);
            //退款类型判断
            if (Objects.equals(RefundDetailTypeCode.GROUP_FEE.getCode(), itemReq.getRefundDetailTypeId())) {
                if (refundAmount.compareTo(touristInfo.getGroupFee()) > 0 ||
                        refundAmount.compareTo(totalPaidIn) > 0) {
                    return Result.failed(SeriesOrderErrorCode.REFUND_AMOUNT_LIMIT);
                }
            } else if (Objects.equals(RefundDetailTypeCode.INSURANCE.getCode(), itemReq.getRefundDetailTypeId())) {
                QueryWrapper<SeriesOrderCollection> queryWrapper3 = new QueryWrapper<>();
                queryWrapper3.lambda().eq(SeriesOrderCollection::getOrderId, req.getOrderId());
                queryWrapper3.lambda().eq(SeriesOrderCollection::getTouristId, req.getTouristId());
                queryWrapper3.lambda().eq(SeriesOrderCollection::getCollectionTypeId, CollectionTypeIdCode.INSURANCE.getCode());
                queryWrapper3.lambda().eq(SeriesOrderCollection::getIsDeleted, IsDeletedCode.NO.getCode());
                SeriesOrderCollection collection = seriesOrderCollectionMapper.selectOne(queryWrapper3);
                if (collection == null) {
                    return Result.failed(SeriesOrderErrorCode.REFUND_NOT_AMOUNT_ERROR);
                }
                if (refundAmount.compareTo(collection.getPaidInAmount()) > 0 ||
                        refundAmount.compareTo(totalPaidIn) > 0) {
                    return Result.failed(SeriesOrderErrorCode.REFUND_AMOUNT_LIMIT);
                }
            } else if (Objects.equals(RefundDetailTypeCode.VISA.getCode(), itemReq.getRefundDetailTypeId())) {
                QueryWrapper<SeriesOrderTouristVisa> queryWrapper3 = new QueryWrapper<>();
                queryWrapper3.lambda().eq(SeriesOrderTouristVisa::getOrderId, req.getOrderId());
                queryWrapper3.lambda().eq(SeriesOrderTouristVisa::getTouristId, req.getTouristId());
                SeriesOrderTouristVisa dbVisa = seriesOrderTouristVisaMapper.selectOne(queryWrapper3);
                if (dbVisa == null) {
                    return Result.failed(SeriesOrderErrorCode.REFUND_NOT_AMOUNT_ERROR);
                }
                if (refundAmount.compareTo(dbVisa.getVisaAmount()) > 0 ||
                        refundAmount.compareTo(totalPaidIn) > 0) {
                    return Result.failed(SeriesOrderErrorCode.REFUND_AMOUNT_LIMIT);
                }
            } else if (Objects.equals(RefundDetailTypeCode.ADJUST.getCode(), itemReq.getRefundDetailTypeId())) {
                if (refundAmount.compareTo(touristInfo.getAdjustmentCost()) > 0 ||
                        refundAmount.compareTo(totalPaidIn) > 0 ||
                        adjustmentCost.compareTo(new BigDecimal(0)) <= 0 ) {
                    return Result.failed(SeriesOrderErrorCode.REFUND_AMOUNT_LIMIT);
                }
            } else if (Objects.equals(RefundDetailTypeCode.COLLECTION.getCode(), itemReq.getRefundDetailTypeId())) {
                if (refundAmount.compareTo(touristInfo.getCollectionFee()) > 0 ||
                        refundAmount.compareTo(totalPaidIn) > 0) {
                    return Result.failed(SeriesOrderErrorCode.REFUND_AMOUNT_LIMIT);
                }
            } else if (Objects.equals(RefundDetailTypeCode.OTHER.getCode(), itemReq.getRefundDetailTypeId())) {
                if (Objects.equals(itemReq.getRefundTypeId(), CollectionRefundWayIdCode.POINTS.getCode())) {
                    MainDataCurrencyUpdateStatusReq cnyCurrencyUpdateStatusReq = new MainDataCurrencyUpdateStatusReq();
                    cnyCurrencyUpdateStatusReq.setId(CurrencyIdCode.CNY.getCode());
                    Result<MainDataCurrencyQueryDTO> cnyCurrencyQueryDTOResult = iMainDataCurrencyService.query(cnyCurrencyUpdateStatusReq);
                    if (!cnyCurrencyQueryDTOResult.isSuccess() || cnyCurrencyQueryDTOResult.getData() == null) {
                        return Result.failed(SystemError.SYS_411);
                    }
                    MainDataCurrencyQueryDTO cnyCurrencyQueryDTO = cnyCurrencyQueryDTOResult.getData();
                    MathContext context = new MathContext(2, RoundingMode.HALF_DOWN);
                    BigDecimal points = (refundAmount.divide(cnyCurrencyQueryDTO.getCrmExchangeRate(), context)).multiply(
                            new BigDecimal(100));

                    QueryWrapper<SeriesOrderCollection> queryWrapper3 = new QueryWrapper<>();
                    queryWrapper3.lambda().eq(SeriesOrderCollection::getOrderId, req.getOrderId());
                    queryWrapper3.lambda().eq(SeriesOrderCollection::getTouristId, req.getTouristId());
                    queryWrapper3.lambda().eq(SeriesOrderCollection::getCollectionWayId, CollectionRefundWayIdCode.POINTS.getCode());
                    queryWrapper3.lambda().eq(SeriesOrderCollection::getIsDeleted, IsDeletedCode.NO.getCode());
                    List<SeriesOrderCollection> collectionList = seriesOrderCollectionMapper.selectList(queryWrapper3);
                    BigDecimal discountAmount = new BigDecimal(0);
                    for (SeriesOrderCollection collection : collectionList) {
                        discountAmount = discountAmount.add(collection.getPaidInAmount());
                    }
                    BigDecimal availablePoints = (discountAmount.divide(cnyCurrencyQueryDTO.getCrmExchangeRate(), context)).multiply(
                            new BigDecimal(100));
                    if (points.compareTo(availablePoints) > 0) {
                        SeriesOrderErrorCode errorCode = SeriesOrderErrorCode.REFUND_POINTS_LIMIT;
                        errorCode.setMsg(String.format(SeriesOrderErrorCode.REFUND_POINTS_LIMIT.getMsg(), availablePoints));
                        return Result.failed(errorCode);
                    }
                } else {
                    if (refundAmount.compareTo(touristInfo.getTotalPaidIn()) > 0 ||
                            refundAmount.compareTo(totalPaidIn) > 0) {
                        return Result.failed(SeriesOrderErrorCode.REFUND_AMOUNT_LIMIT);
                    }
                }
            }

            //每次扣减
            totalPaidIn = totalPaidIn.subtract(refundAmount);

            detail.setRefundId(refundId);
            detail.setRefundNumber(iSeriesOrderService.getRefundNumber());
            detail.setRefundStatus(2);
            detail.setTotalReceivables(touristInfo.getTotalReceivables());
            detail.setPaidInAmount(touristInfo.getTotalPaidIn());
            detail.setActualRefundAmount(BigDecimal.ZERO);
            detail.setGmtCreate(now);
            detail.setGmtModified(now);
            detail.setCreateId(req.getUserId());
            detail.setModifiedId(req.getUserId());
            detail.setIsDeleted(IsDeletedCode.NO.getCode());
            detail.setRefundAmount(refundAmount);
            refundDetailList.add(detail);
            refundIdList.add(refundId);
        }
        //批量新增收款明细
        Integer batch = seriesOrderTouristRefundDetailMapper.insertBatchSomeColumn(refundDetailList);
        if (batch < refundDetailList.size()){
            throw new BusinessException(SystemError.SYS_437);
        }
        refund.setRefundAmount(totalRefundAmount);
        Map<String, Object> extendParams = new HashMap<>();
        extendParams.put("id", refund.getId());
        Result<ApprovalStartDTO> approvalResult = iSysApprovalService.start(SystemBusinessType.OUTBOUND_TRAVEL.getCode(),
                SysApprovalType.REFUND_OUTTRA.getCode(), req.getOrderId(),
                req.getUserId(), null, JSON.toJSONString(extendParams));
        if (!approvalResult.isSuccess()) {
            log.error(approvalResult.getMsg());
            throw new BusinessException(SystemError.SYS_500);
        }
        refund.setApprovalId(approvalResult.getData().getApprovalId());
        boolean update = updateById(refund);
        if (!update){
            throw new BusinessException(SystemError.SYS_437);
        }
        return Result.success(refundIdList);
    }

    /**
     * 添加计算
     */
    public Result addCalculation(SeriesOrderTouristRefundAddCalculationReq req) {
        QueryWrapper<SeriesOrderAmountStatistics> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(SeriesOrderAmountStatistics::getOrderId, req.getOrderId());
        SeriesOrderAmountStatistics statistics = seriesOrderAmountStatisticsMapper.selectOne(queryWrapper);
        if (statistics == null) {
            return Result.failed(SystemError.SYS_411);
        }
        //实收金额
        BigDecimal totalPaidIn = statistics.getTotalPaidIn();
        //查询优惠金额
        BigDecimal discountAmount = new BigDecimal(0);
        QueryWrapper<SeriesOrderCollection> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.lambda().eq(SeriesOrderCollection::getOrderId, req.getOrderId());
        queryWrapper2.lambda().eq(SeriesOrderCollection::getTouristId, req.getTouristId());
        queryWrapper2.lambda().and(object -> object.eq(SeriesOrderCollection::getCollectionWayId, CollectionRefundWayIdCode.BANK_PREFERENCE.getCode())
//                .or().eq(SeriesOrderCollection::getCollectionWayId, CollectionRefundWayIdCode.POINTS.getCode())
                .or().eq(SeriesOrderCollection::getCollectionWayId, CollectionRefundWayIdCode.OPERATE_PROMOTION.getCode()));
        queryWrapper2.lambda().eq(SeriesOrderCollection::getIsDeleted, IsDeletedCode.NO.getCode());
        List<SeriesOrderCollection> collectionList = seriesOrderCollectionMapper.selectList(queryWrapper2);
        for (SeriesOrderCollection collection : collectionList) {
            discountAmount = discountAmount.add(collection.getPaidInAmount());
        }

        BigDecimal totalAmount = new BigDecimal(0);
        SeriesOrderTouristRefundAddCalculationDTO dto = EntityUtil.copy(req, SeriesOrderTouristRefundAddCalculationDTO.class);

        for (SeriesOrderTouristRefundAddCalculationItemReq calculationItemReq : req.getItemList()) {
            if (calculationItemReq.getCurrencyTypeId() == null ||
                    Objects.equals(CurrencyIdCode.HKD.getCode(), calculationItemReq.getCurrencyTypeId())) {
                totalAmount = totalAmount.add(calculationItemReq.getCurrencyRefundAmount());
            } else {
                MainDataCurrencyUpdateStatusReq currencyUpdateStatusReq = new MainDataCurrencyUpdateStatusReq();
                currencyUpdateStatusReq.setId(calculationItemReq.getCurrencyTypeId());
                Result<MainDataCurrencyQueryDTO> currencyQueryDTOResult = iMainDataCurrencyService.query(currencyUpdateStatusReq);
                if (!currencyQueryDTOResult.isSuccess() && currencyQueryDTOResult.getData() == null) {
                    return Result.failed(SystemError.SYS_411);
                }
                MainDataCurrencyQueryDTO currencyQueryDTO = currencyQueryDTOResult.getData();
                MathContext context = new MathContext(2, RoundingMode.HALF_DOWN);
                //其他貨幣金額=港幣金額÷對應的門市匯率
                BigDecimal refundAmount = calculationItemReq.getCurrencyRefundAmount().divide(currencyQueryDTO.getMarketExchangeRate(), context);
                totalAmount = totalAmount.add(refundAmount);
            }
        }
        dto.setTotalPaidIn(totalPaidIn);
        dto.setDiscountAmount(discountAmount);
        dto.setTotalAmount(totalAmount);
        return Result.success(dto);
    }

    /**
     * 操作退款
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result confirm(SeriesOrderTouristRefundConfirmReq req, TokenUser currentUser) {
        SeriesOrderTouristRefundDetail detail = seriesOrderTouristRefundDetailMapper.selectById(req.getId());
        if (detail == null || Objects.equals(detail.getIsDeleted(),1)){
            throw new BusinessException(SystemError.CUSTOM_ORDER_4049);
        }
        //审批通过才能操作退款
        if (!Objects.equals(detail.getRefundStatus(),3)){
            throw new BusinessException(SystemError.CUSTOM_ORDER_4021);
        }
        detail.setRefundStatus(5);
        detail.setModifiedId(currentUser.getId());
        Integer update = seriesOrderTouristRefundDetailMapper.updateById(detail);
        if (update <= 0){
            throw new BusinessException(SystemError.SYS_437);
        }
        //更新统计
        SeriesOrderTouristRefund refund = getById(detail.getRefundId());
        SeriesOrderTouristInfo touristInfo = seriesOrderTouristInfoMapper.selectById(refund.getTouristId());
        touristInfo.setTotalPaidIn(touristInfo.getTotalPaidIn().subtract(detail.getRefundAmount()));
        touristInfo.setRefundAmount(touristInfo.getRefundAmount().add(detail.getRefundAmount()));
        touristInfo.setModifiedId(currentUser.getId());
        int update1 = seriesOrderTouristInfoMapper.updateById(touristInfo);
        QueryWrapper<SeriesOrderAmountStatistics> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_id",refund.getOrderId());
        SeriesOrderAmountStatistics amountStatistics = seriesOrderAmountStatisticsMapper.selectOne(queryWrapper);
        amountStatistics.setTotalPaidIn(amountStatistics.getTotalPaidIn().subtract(detail.getRefundAmount()));
        amountStatistics.setRefundAmount(amountStatistics.getRefundAmount().add(detail.getRefundAmount()));
        int update2 = seriesOrderAmountStatisticsMapper.updateById(amountStatistics);
        if (update1 <= 0 || update2 <= 0){
            throw new BusinessException(SystemError.SYS_437);
        }
        //其他费用
        SeriesOrderTouristOtherFee otherFee = new SeriesOrderTouristOtherFee();
        otherFee.setId(SnowflakeIdWorker.nextId());
        otherFee.setFeeType(1);
        otherFee.setFeeName("退款");
        otherFee.setOrderId(touristInfo.getOrderId());
        otherFee.setTouristId(touristInfo.getId());
        otherFee.setRelationId(detail.getId());
        otherFee.setAmount(detail.getActualRefundAmount());
        otherFee.setGmtCreate(LocalDateTime.now());
        otherFee.setCreateId(currentUser.getId());
        otherFee.setIsDeleted(0);
        int insert = seriesOrderTouristOtherFeeMapper.insert(otherFee);
        if (insert <= 0){
            throw new BusinessException(SystemError.SYS_437);
        }
        //对接财务操作退款
        BillOperateRefundReq req1 = new BillOperateRefundReq();
        req1.setBillNumber(detail.getRefundNumber());
        req1.setBusinessType(SystemBusinessType.OUTBOUND_TRAVEL.getCode());
        req1.setUserId(currentUser.getId());
        Result result = financeBillService.operateRefund(req1);
        if (result == null || !result.isSuccess()){
            throw new BusinessException(SystemError.SYS_437);
        }
        return Result.success(detail.getId());
    }


    /**
     * 审核
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result approval(SeriesOrderTouristRefundApprovalReq req) {
        QueryWrapper<SeriesOrderTouristRefund> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("approval_id",req.getApprovalId());
        queryWrapper.eq("is_deleted",0);
        SeriesOrderTouristRefund refund = seriesOrderTouristRefundMapper.selectOne(queryWrapper);
        if (refund == null){
            throw new BusinessException(SystemError.SYS_411);
        }
        refund.setModifiedId(req.getUserId());
        if (Objects.equals(req.getApprovalStatus(),0)){
            //撤回
            refund.setIsDeleted(1);
            boolean update = updateById(refund);
            if (!update){
                throw new BusinessException(SystemError.SYS_437);
            }
            //批量删除退款明细
            seriesOrderTouristRefundDetailMapper.batchDelByRefundId(refund.getId(),req.getUserId());
            return Result.success(refund.getId());
        }
        refund.setRefundStatus(req.getApprovalStatus());
        boolean update = updateById(refund);
        if (!update){
            throw new BusinessException(SystemError.SYS_437);
        }
        if (Objects.equals(req.getApprovalStatus(),3)){
            //审批通过
            if (CollectionUtils.isNotEmpty(req.getRefundAmountList())){
                List<BillAddRefundReq> reqList = new ArrayList<>();
                for (RefundAmountReq req2 : req.getRefundAmountList()){
                    SeriesOrderTouristRefundDetail detail = seriesOrderTouristRefundDetailMapper.selectById(req2.getId());
                    if (detail != null && Objects.equals(detail.getIsDeleted(),0)){
                        detail.setRefundStatus(req.getApprovalStatus());
                        if (req2.getRefundAmount().compareTo(detail.getRefundAmount()) > 0){
                            throw new BusinessException(SystemError.TOUR_ORDER_30027);
                        }
                        //修改退款订单详情 实际退款金额
                        detail.setActualRefundAmount(req2.getRefundAmount());
                        detail.setModifiedId(req.getUserId());
                        int update1 = seriesOrderTouristRefundDetailMapper.updateById(detail);
                        if (update1 <= 0){
                            throw new BusinessException(SystemError.SYS_437);
                        }
                        //根据详情查询退款单
                        SeriesOrderTouristRefund seriesOrderTouristRefund = seriesOrderTouristRefundMapper.selectById(detail.getRefundId());
                        //更新统计订单的总退款金额和总实收金额
                        SeriesOrderAmountStatistics seriesOrderAmountStatistics = seriesOrderAmountStatisticsMapper.selectByOrderId(seriesOrderTouristRefund.getOrderId());
                        if(org.springframework.util.StringUtils.isEmpty(seriesOrderAmountStatistics)){
                            throw new BusinessException(SystemError.IOTC_40009);
                        }
                        BigDecimal refundAmount = seriesOrderAmountStatistics.getRefundAmount();
                        if(org.springframework.util.StringUtils.isEmpty(refundAmount)){
                            refundAmount = BigDecimal.ZERO;
                        }
                        seriesOrderAmountStatistics.setRefundAmount(refundAmount.add(req2.getRefundAmount()));//已退款金额+退款金额
                        BigDecimal totalPaidIn = seriesOrderAmountStatistics.getTotalPaidIn();
                        if(org.springframework.util.StringUtils.isEmpty(totalPaidIn)){
                            totalPaidIn = BigDecimal.ZERO;
                        }
                        seriesOrderAmountStatistics.setTotalPaidIn(totalPaidIn.subtract(req2.getRefundAmount()));//总实收金额- 退款金额
                        int update2 = seriesOrderAmountStatisticsMapper.updateById(seriesOrderAmountStatistics);
                        if (update2 <= 0){
                            throw new BusinessException(SystemError.SYS_437);
                        }
                        //更新游客订单的退款金额和实收金额
                        SeriesOrderTouristInfo seriesOrderTouristInfo = seriesOrderTouristInfoMapper.selectById(seriesOrderTouristRefund.getTouristId());
                        if(org.springframework.util.StringUtils.isEmpty(seriesOrderTouristInfo)){
                            throw new BusinessException(SystemError.IOTC_40009);
                        }
                        //已退款金额+退款金额
                        BigDecimal refundAmount1 = seriesOrderAmountStatistics.getRefundAmount();
                        if(org.springframework.util.StringUtils.isEmpty(refundAmount1)){
                            refundAmount1 = BigDecimal.ZERO;
                        }
                        seriesOrderTouristInfo.setRefundAmount(refundAmount1.add(req2.getRefundAmount()));
                        BigDecimal totalPaidIn1 = seriesOrderTouristInfo.getTotalPaidIn();
                        //总实收金额- 退款金额
                        if(org.springframework.util.StringUtils.isEmpty(totalPaidIn1)){
                            totalPaidIn1 = BigDecimal.ZERO;
                        }
                        seriesOrderTouristInfo.setTotalPaidIn(totalPaidIn1.subtract(req2.getRefundAmount()));
                        int update3 = seriesOrderTouristInfoMapper.updateById(seriesOrderTouristInfo);
                        if (update3 <= 0){
                            throw new BusinessException(SystemError.SYS_437);
                        }
                        //审批通过，对接财务中心新增退款认款
                        SeriesOrder order = seriesOrderMapper.selectById(refund.getOrderId());
                        SeriesTripScheduleDTO tripSchedule = iSeriesTripScheduleService.getTripScheduleId(refund.getScheduleId());
                        UserDTO userDTO = iSysUserService.queryCacheUser(detail.getCreateId());
                        //新增退款认款请求参数
                        BillAddRefundReq req1 = packBillAddRefundReq(refund,detail,order,tripSchedule,userDTO,req.getUserId());
                        reqList.add(req1);
                    }
                }
                //批量新增财务退款记录
                Result result = financeBillService.addRefund(reqList);
                if (result == null || !result.isSuccess()){
                    throw new BusinessException(SystemError.SYS_437);
                }
            }
        }
        Result<ApprovalCheckDTO> result = iSysApprovalService.check(req.getApprovalId(), req.getUserId(),
                req.getApprovalStatus(), req.getComments());
        if (!result.isSuccess()) {
            throw new BusinessException(SystemError.SYS_437);
        }
        return Result.success(refund.getId());
    }

    /**
     * 新增退款认款请求参数(财务中心)
     * @param refund
     * @param detail
     * @param order
     * @param tripSchedule
     * @param userDTO
     * @param userId
     * @return
     */
    private BillAddRefundReq packBillAddRefundReq(SeriesOrderTouristRefund refund, SeriesOrderTouristRefundDetail detail, SeriesOrder order, SeriesTripScheduleDTO tripSchedule, UserDTO userDTO, Long userId) {
        BillAddRefundReq req1 = new BillAddRefundReq();
        req1.setBillNumber(detail.getRefundNumber());
        req1.setBusinessType(SystemBusinessType.OUTBOUND_TRAVEL.getCode());
        req1.setCollectionAmount(detail.getActualRefundAmount());
        req1.setCurrencyId(detail.getCurrencyTypeId());
        req1.setCurrencyName(detail.getCurrencyType());
        req1.setExchangeRate(detail.getExchangeRate().doubleValue());
        req1.setSaleOrderNumber(order.getOrderNumber());
        req1.setSaleOrderId(order.getId());
        req1.setProductNumber(tripSchedule.getTripNumber());
        req1.setProductName(tripSchedule.getSeriesTripScheduleDataDTO().getTitle());
        List<String> resourceInfo = new ArrayList<>();
        resourceInfo.add(tripSchedule.getSeriesTripScheduleDataDTO().getTitle());
        req1.setResourceInfo(resourceInfo);
        req1.setSaleUserId(refund.getCreateId());
        req1.setSaleDeptId(userDTO.getDeptId());
        req1.setSaleUserName(userDTO.getFullName());
        req1.setRefundTypeId(detail.getRefundDetailTypeId());
        req1.setRefundType(detail.getRefundDetailType());
        req1.setTypeId(detail.getRefundTypeId());
        req1.setType(detail.getRefundType());
        AccountJson refundAccountJson = new AccountJson();
        refundAccountJson.setCardNumber(detail.getRefundAccount());
        req1.setRefundAccountJson(refundAccountJson);
        req1.setRefundTime(refund.getGmtCreate());
        req1.setRefundRemark(detail.getRemark());
        req1.setUserId(userId);
        req1.setScheduleId(tripSchedule.getId());
        return req1;
    }

    /**
     * 退款(内部接口)
     * @param refundNumber
     * @param tokenUser
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<Long> confirmRefund(String refundNumber, TokenUser tokenUser) {
    	validateNotBlank(refundNumber);
    	QueryWrapper<SeriesOrderTouristRefundDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("refund_number",refundNumber);
        queryWrapper.eq("is_deleted",0);
        SeriesOrderTouristRefundDetail detail = seriesOrderTouristRefundDetailMapper.selectOne(queryWrapper);
    	if (detail == null){
    	    throw new BusinessException(SystemError.SYS_411);
        }
    	//审批通过才能操作退款
        if (!Objects.equals(detail.getRefundStatus(),3)){
            throw new BusinessException(SystemError.CUSTOM_ORDER_4021);
        }

        detail.setRefundStatus(5);
        detail.setModifiedId(tokenUser.getId());
    //    fillUpdateEntity(entity, tokenUser);

        int update = seriesOrderTouristRefundDetailMapper.updateById(detail);
        if (update <= 0){
            throw new BusinessException(SystemError.SYS_437);
        }
        return newResult(detail.getId());
    }

    /**
     * 财务中心-销售订单退款-退款详情-退款明细列表（内部接口）
     *
     * @param refundNumber 退款单号
     * @return
     */
    @Override
    public Result<List<OrderRefundDTO>> refundDetailList(String refundNumber) {
        QueryWrapper<SeriesOrderTouristRefundDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("refund_number",refundNumber);
        queryWrapper.eq("is_deleted",0);
        SeriesOrderTouristRefundDetail detail = seriesOrderTouristRefundDetailMapper.selectOne(queryWrapper);
        if (detail == null){
            throw new BusinessException(SystemError.CUSTOM_ORDER_4049);
        }
        //退款信息列表
        List<OrderRefundDTO> list = seriesOrderTouristRefundDetailMapper.queryListByRefund(detail.getRefundId());
        if (CollectionUtils.isNotEmpty(list)){
            list.forEach(dto -> {
                //业务类型
                dto.setBusinessType(SystemBusinessType.OUTBOUND_TRAVEL.getCode());
            });
        }
        return Result.success(list);
    }

    /**
     * 审批中心-退款信息列表
     *
     * @param req
     * @return
     */
    @Override
    public Result<List<ApprovalRefundListDTO>> approvalRefundList(ApprovalIdReq req) {
        QueryWrapper<SeriesOrderTouristRefund> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("approval_id",req.getApprovalId());
        queryWrapper.eq("is_deleted",0);
        SeriesOrderTouristRefund refund = seriesOrderTouristRefundMapper.selectOne(queryWrapper);
        if (refund == null){
            throw new BusinessException(SystemError.SYS_411);
        }
        QueryWrapper<SeriesOrderTouristRefundDetail> detailQueryWrapper = new QueryWrapper<>();
        detailQueryWrapper.eq("refund_id",refund.getId());
        detailQueryWrapper.eq("is_deleted",0);
        List<SeriesOrderTouristRefundDetail> detailList = seriesOrderTouristRefundDetailMapper.selectList(detailQueryWrapper);
        List<ApprovalRefundListDTO> dtoList = new ArrayList<>();
        for (SeriesOrderTouristRefundDetail detail : detailList){
            ApprovalRefundListDTO dto = EntityUtil.copy(detail,ApprovalRefundListDTO.class);
            dto.setRefundWay(detail.getRefundType());
            if (detail.getCreateId() != null){
                UserDTO userDTO = iSysUserService.queryCacheUser(detail.getCreateId());
                if (userDTO != null){
                    dto.setApprovalUser(userDTO.getFullName());
                    dto.setCreateUserDept(userDTO.getDept());
                }
                dtoList.add(dto);
            }
        }
        return Result.success(dtoList);
    }
}
